﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using Hydra.Shell.Implementations;
using SLControlLibrary;
using Hydra.UrlMon.Interfaces;
using Hydra.Shell.Interfaces;
using Hydra.UrlMon.Enumerations;
using Hydra.UrlMon.Implementation;
using Hydra.Shell.Attributes;
using AbstraX.ClientInterfaces;
using Hydra.Shell;
using Utils;
using System.Text.RegularExpressions;
using System.IO;
using Hydra.Shell.Constants;

namespace AbstraX.ProtocolHandlers
{
    [Guid("272D8435-7565-409A-8176-FF9D0BA3BFE5")]
    public class AbstraXProtocolHandler : HydraServiceBase<AbstraXProtocolHandler>, IInternetProtocol, IClassFactory, IObjectWithSite
    {
        private IHydraUIInternals hydraUIInternals;
        private IUnknown site;
        private IBase baseObject;

        public AbstraXProtocolHandler(UIThread uiThread) : base(uiThread)
        {
        }

        public IUnknown CreateInstance(object pOuterUnk, Guid iid)
        {
            IUnknown pUnk;
            var extension = baseObject.LoadExtension(baseObject);

            if (extension.QueryInterface(iid, out pUnk))
            {
                return pUnk;
            }
            else
            {
                throw new NotImplementedException();
            }
        }

        public void LockServer(bool Lock)
        {
            throw new NotImplementedException();
        }

        public int Read(IntPtr pv, int cb, out int pcbRead)
        {
            throw new NotImplementedException();
        }

        public void Seek(long dlibMove, int dwOrigin, out long plibNewPosition)
        {
            throw new NotImplementedException();
        }

        public void LockRequest(int dwOptions)
        {
            throw new NotImplementedException();
        }

        public void UnlockRequest()
        {
            throw new NotImplementedException();
        }

        public void Start(string szUrl, IInternetProtocolSink pOIProtSink, IInternetBindInfo pOIBindInfo, ProtocolFlags grfPI, int dwReserved)
        {
            var guid = typeof(IAbstraXDocumentSave).GetGuid();
            var documentMk = string.Empty;
            var regex = new Regex(@".*\[\@URL='(?<url>.+?)'\]");
            var match = regex.Match(szUrl);
            var url = match.Groups["url"].Value;

            if (szUrl.StartsWith(url))
            {
                szUrl = szUrl.RemoveStart(url);
            }

            regex = new Regex(@".*?\.(?<ext>[\w-]+?)$");
            match = regex.Match(szUrl);

            var id = string.Empty;

            if (match.Success)
            {
                id = szUrl.RemoveEnd(match.Groups["ext"].Value.Length + 1);
            }

            var operation = hydraUIInternals.GenerateAbstraXItemFromID(id);

            pOIProtSink.ReportProgress(BindStatus.BEGINDOWNLOADDATA, "Download initiated.");

            operation.OnProgress += (sender, e) =>
            {
                pOIProtSink.ReportData(BindStatusCallbackFlags.AVAILABLEDATASIZEUNKNOWN, (int)(e.PercentComplete * 100), 100);
            };

            operation.ExceptionOccured += (sender, e) =>
            {
                pOIProtSink.ReportResult(CommonStatusCodes.E_FAIL, 0, e.Exception.Message);
            };

            operation.Generated += (sender, e) =>
            {
                baseObject = (IBase) e.Item;

                pOIProtSink.ReportResult(CommonStatusCodes.S_OK, 0, "Download complete.");
                pOIProtSink.ReportData(BindStatusCallbackFlags.DATAFULLYAVAILABLE, 100, 100);
                pOIProtSink.ReportProgress(BindStatus.IUNKNOWNAVAILABLE, "Object available.");
            };
        }

        public void Continue(ref ProtocolData pProtocolData)
        {
            throw new NotImplementedException();
        }

        public void Abort(int hrReason, int dwOptions)
        {
            throw new NotImplementedException();
        }

        public void Terminate(int dwOptions)
        {
            throw new NotImplementedException();
        }

        public void Suspend()
        {
            throw new NotImplementedException();
        }

        public void Resume()
        {
            throw new NotImplementedException();
        }

        public void SetSite(IUnknown pUnkSite)
        {
            site = pUnkSite;

            site.QueryInterface<IHydraUIInternals>(out hydraUIInternals);
        }

        public bool GetSite(Guid riid, out IUnknown ppvSite)
        {
            ppvSite = site;
            return true;
        }

        public bool GetSite<T>(Guid riid, out T ppvSite)
        {
            ppvSite = (T) site;
            return true;
        }
    }
}
